package world3d.world;

import com.jogamp.opengl.util.Animator;

import javax.media.opengl.*;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class World implements GLEventListener {
	private List<Entity> entities = new ArrayList<Entity>();
	private GLAutoDrawable glAutoDrawable;
	private final GLCanvas canvas;
	private final Animator animator;
	private int width;
	private int height;

	public World(GLCanvas canvas) {
		animator = new Animator(canvas);
		this.canvas = canvas;
		animator.start();
		this.canvas.addGLEventListener(this);
		this.canvas.requestFocus();
	}

	public void addEntity(Entity entity){
		entities.add(entity);
		if(glAutoDrawable != null){
			entity.init(glAutoDrawable);
		}
	}

	@Override
	public void init(GLAutoDrawable glAutoDrawable) {
		this.glAutoDrawable = glAutoDrawable;
		GL2 gl = glAutoDrawable.getGL().getGL2();
		gl.glShadeModel(GLLightingFunc.GL_SMOOTH);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.glClearDepth(1.0f);
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthFunc(GL.GL_LEQUAL);
		gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);

		for (Entity entity : entities) {
			entity.init(glAutoDrawable);
			entity.setIsInit();
		}
	}

	@Override
	public void dispose(GLAutoDrawable glAutoDrawable) {
		for (Entity entity : entities) {
			entity.dispose();
		}
		this.canvas.removeGLEventListener(this);
	}
	private float rotateX = 0.0f;
	private float rotateY = 0.0f;
	private float visibleRotateX = 0.0f;
	private float visibleRotateY = 0.0f;
	private float scaleT = -4.0f;
	@Override
	public void display(GLAutoDrawable glAutoDrawable) {
		final GL2 gl = glAutoDrawable.getGL().getGL2();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		gl.glClear(GL.GL_DEPTH_BUFFER_BIT);

		gl.glLoadIdentity();
//		gl.glTranslatef(0.0f, 0.0f, -5.0f);
		gl.glTranslatef(-0.5f, -0.5f, scaleT);

		// rotate by mouse
		visibleRotateX += (rotateX - visibleRotateX) * .1;
		visibleRotateY += (rotateY - visibleRotateY) * .1;
		gl.glRotatef(visibleRotateX, 1.0f, 0, 0);
		gl.glRotatef(visibleRotateY, 0.0f, 1.0f, 0.0f);
		gl.glRotatef(0, 0.0f, 0.0f, 1.0f);
		PointerInfo pointerInfo = MouseInfo.getPointerInfo();
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		rotateY = (float) ((width / screenSize.getWidth()) * pointerInfo.getLocation().getX());
		rotateX = (float) ((height / screenSize.getHeight()) * pointerInfo.getLocation().getY());

		for (Entity entity : entities) {
			if(entity.isInit()) {
				entity.display();
			}
		}
	}

	@Override
	public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) {
		this.width = width;
		this.height = height;
		GL2 gl = glAutoDrawable.getGL().getGL2();
		final float aspect = (float) width / (float) height;
		gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
		gl.glLoadIdentity();
		final float fh = 0.5f;
		final float fw = fh * aspect;
		gl.glFrustumf(-fw, fw, -fh, fh, 1.0f, 1000.0f);
		gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
//		gl.glMatrixMode(GLMatrixFunc.GL_TEXTURE_MATRIX);
		gl.glLoadIdentity();

		for (Entity entity : entities) {
			entity.reshape(x, y, width, height);
		}
	}

	public void dispose() {
		dispose(glAutoDrawable);
		animator.stop();
	}
}
